home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Mac Power 1997 December
/
MACPOWER-1997-12.ISO.7z
/
MACPOWER-1997-12.ISO
/
AMUG
/
PROGRAMMING
/
Raven 1.2 Examples.sit
/
Raven 1.2 Examples
/
Quill
/
Source
/
ViewContainer.cpp
< prev
next >
Wrap
Text File
|
1997-09-03
|
54KB
|
2,066 lines
/*
* File: ViewContainer.h
* Summary: A view containing the panes to be edited.
* Written by: Jesse Jones
*
* Copyright ゥ 1996-1997 Jesse Jones.
* For conditions of distribution and use, see copyright notice in ZTypes.h
*
* Change History (most recent first):
*
* <4> 8/12/97 JDJ Added context menus.
* <3> 4/06/97 JDJ Updated for new style TSubPaneIterator.
* <2> 4/06/97 JDJ Overrides HandleMouseDown and co to prevent
* mouse events from reaching sub panes.
* <1> 8/26/96 JDJ Created
*/
#include "ViewContainer.h"
#include <Algorithm.h>
#include <List.h>
#include <Map.h>
#include <ToolUtils.h>
#include <Vector.h>
#include <ZApplication.h>
#include <ZAttributes.h>
#include <ZCommands.h>
#include <ZContextMenu.h>
#include <ZDragSession.h>
#include <ZHandleStream.h>
#include <ZInput.h>
#include <ZLocker.h>
#include <ZMiscUtils.h>
#include <ZPaneTrackers.h>
#include <ZQDShapes.h>
#include <ZQuickDrawUtils.h>
#include <ZScrap.h>
#include <ZStateBroadcaster.h>
#include <ZStringUtils.h>
#include <ZUndoMgr.h>
#include <ZWindow.h>
#include "Constants.h"
#include "Document.h"
#include "GridSizeDialog.h"
#include "PaneEditDialog.h"
#include "ViewCommands.h"
#include "ViewDecorations.h"
#include "ViewTrackers.h"
#include "ViewWindow.h"
__MSL_FIX_ITERATORS__(TPane* const);
//-----------------------------------
// Misc Commands
//
const short kSpaceKeyCode = 0x31;
//-----------------------------------
// Menu Commands
//
const MenuCommand kShowGridCmd = "Show Grid";
const MenuCommand kShowPaneNamesCmd = "Show Pane Names";
const MenuCommand kShowClassNamesCmd = "Show Class Names";
const MenuCommand kShowPaneEdgesCmd = "Show Pane Edges";
const MenuCommand kSnapToGridCmd = "Snap to Grid";
const MenuCommand kEditGridCmd = "Edit Grid";
const MenuCommand kAlignLeftCmd = "Align Left";
const MenuCommand kAlignRightCmd = "Align Right";
const MenuCommand kAlignTopCmd = "Align Top";
const MenuCommand kAlignBottomCmd = "Align Bottom";
// ===================================================================================
// Helper Functions
// ===================================================================================
//---------------------------------------------------------------
//
// GetGridSize
//
//---------------------------------------------------------------
static bool GetGridSize(TSize* size)
{
bool got = false;
TSize newSize = *size;
if (GetShort(LoadAppString("Grid Width"), 4, &newSize.width, 64)) {
if (GetShort(LoadAppString("Grid Height"), 4, &newSize.height, 64)) {
*size = newSize;
got = true;
}
}
return got;
}
#pragma mark -
// ===================================================================================
// class CTabBehavior
// ===================================================================================
class CTabBehavior : public TBehavior<TKeyEvent> {
typedef TBehavior<TKeyEvent> Inherited;
//-----------------------------------
// Initialization/Destruction
//
public:
virtual ~CTabBehavior();
CTabBehavior();
//-----------------------------------
// TBehavior API
//
protected:
virtual bool OnExecute(TKeyEvent& event);
virtual void OnAttached(MBehaviorableBase* owner);
//-----------------------------------
// Types
//
protected:
typedef vector<TPane*, allocator<TPane*> > PaneList;
//-----------------------------------
// Internal API
//
public:
virtual void RotateTarget(bool forward = true);
protected:
virtual PaneList* CreateTargetList(TPane* target);
//-----------------------------------
// Member data
//
protected:
CViewContainer* mContainer;
};
//---------------------------------------------------------------
//
// CTabBehavior::~CTabBehavior
//
//---------------------------------------------------------------
CTabBehavior::~CTabBehavior()
{
}
//---------------------------------------------------------------
//
// CTabBehavior::CTabBehavior
//
//---------------------------------------------------------------
CTabBehavior::CTabBehavior() : TBehavior<TKeyEvent>("CTabBehavior", kNonPersistant)
{
mContainer = nil;
}
//---------------------------------------------------------------
//
// CTabBehavior::OnAttached
//
//---------------------------------------------------------------
void CTabBehavior::OnAttached(MBehaviorableBase* owner)
{
Inherited::OnAttached(owner);
mContainer = dynamic_cast<CViewContainer*>(owner);
ASSERT(mContainer != nil);
}
//---------------------------------------------------------------
//
// CTabBehavior::OnExecute
//
//---------------------------------------------------------------
bool CTabBehavior::OnExecute(TKeyEvent& event)
{
bool handled = false;
if (event.WasKeyDown() && event.GetChar() == kTabChar) {
this->RotateTarget(!event.WasShiftKeyDown());
handled = true;
}
return handled;
}
//---------------------------------------------------------------
//
// CTabBehavior::RotateTarget
//
//---------------------------------------------------------------
void CTabBehavior::RotateTarget(bool forward)
{
try {
// Find the first selected pane.
TPane* target = nil;
TSubPaneIterator iter = mContainer->begin(kRecursive);
while (iter != mContainer->end() && target == nil) {
TPane* subPane = *iter;
++iter;
if (mContainer->IsSelected(subPane))
target = subPane;
}
// Get a list of the panes to switch among.
TAutoPtr<PaneList> panes(this->CreateTargetList(target));
long count = panes->size();
// Find out the index of the selected pane.
PaneList::iterator paneIter = find(panes->begin(), panes->end(), target);
long targetIndex = paneIter - panes->begin();
TPane* newTarget = nil;
// If there isn't a selected pane make the first pane the target.
if (target == nil && count > 0)
if (forward)
newTarget = panes->at(0);
else
newTarget = panes->at(count-1);
// If a subPane has the target select the next subPane.
else if (target != nil && targetIndex >= 0 && count > 1)
if (forward)
if (targetIndex+1 < count)
newTarget = panes->at(targetIndex+1);
else
newTarget = panes->at(0);
else
if (targetIndex > 0)
newTarget = panes->at(targetIndex-1);
else
newTarget = panes->at(count-1);
// If a subPane has the target, but there isn't another
// subPane that can become the target don't change the
// target.
else if (target != nil && targetIndex >= 0 && count == 1)
newTarget = target;
// Change the target.
if (newTarget != target)
mContainer->Select(newTarget);
} catch (const TBaseException& e) {
ReportError(LoadAppString("Couldn't switch to the next pane"), e);
} catch(...) {
ReportError(LoadAppString("Couldn't switch to the next pane"), LoadAppString("Unknown Error"));
}
}
//---------------------------------------------------------------
//
// CTabBehavior::CreateTargetList
//
//---------------------------------------------------------------
CTabBehavior::PaneList* CTabBehavior::CreateTargetList(TPane* target)
{
PaneList* panes = new PaneList;
TView* view = target != nil ? target->GetSuperView() : mContainer;
// Put all of visible subPanes of view in the list.
TSubPaneIterator iter = view->begin();
while (iter != view->end()) {
TPane* subPane = *iter;
++iter;
if (subPane->IsVisible())
panes->push_back(subPane);
}
return panes;
}
#pragma mark -
// ===================================================================================
// struct SResourceID
// ===================================================================================
struct SResourceID {
ResType type;
ResID id;
SResourceID() {type = '????'; id = 0;}
SResourceID(ResType t, ResID i) {type = t; id = i;}
bool operator==(const SResourceID& rhs) const {return type == rhs.type && id == rhs.id;}
bool operator<(const SResourceID& rhs) const {return type < rhs.type || (type == rhs.type && id < rhs.id);}
};
// ===================================================================================
// class CViewContainer
// ===================================================================================
static TReanimatorRegister<CViewContainer> sContainerRegistrar;
typedef map<SResourceID, CViewContainer*, less<SResourceID>, allocator<CViewContainer*> > ContainerMap;
static ContainerMap sContainers;
typedef pair<const SResourceID, CViewContainer*> ContainerEntry;
//---------------------------------------------------------------
//
// CViewContainer::~CViewContainer
//
//---------------------------------------------------------------
CViewContainer::~CViewContainer()
{
if (mType != '????')
ASSERT(sContainers.count(SResourceID(mType, mRsrcID)) == 1);
this->UpdateResource();
if (mType != '????')
sContainers.erase(SResourceID(mType, mRsrcID));
if (mSuperView != nil) // do this here to maintain CViewWindow's invariant
mSuperView->RemoveSubPane(this);
if (mDoc != nil)
mDoc->RemoveReference();
}
//---------------------------------------------------------------
//
// CViewContainer::CViewContainer (TWindow*)
//
//---------------------------------------------------------------
CViewContainer::CViewContainer(TWindow* wind) : TCachedView("CViewContainer", nil, wind->GetExtent()), MCommander(wind)
{
ASSERT(wind != nil);
mBinding.left = true;
mBinding.right = true;
mBinding.top = true;
mBinding.bottom = true;
wind->AddSubPane(this); // do this here so we're the right type
mDoc = nil;
mRsrcMap = nil;
mType = '????';
mRsrcID = 0;
mSettingUp = false;
mSnapToGrid = true;
mShowGrid = true;
mGridSize = TSize(10, 10);
mShowPaneNames = false;
mShowClassNames = false;
mShowPaneEdges = true;
wind->SetLatentTarget(this);
MCommander::AddBehaviorToFront(new CTabBehavior);
}
//---------------------------------------------------------------
//
// CViewContainer::CViewContainer (TWindow*, CResourceMap*, ResID)
//
//---------------------------------------------------------------
CViewContainer::CViewContainer(TWindow* wind, CResourceMap* rsrcMap, ResID id) : TCachedView("CViewContainer", nil, wind->GetExtent()), MCommander(wind)
{
ASSERT(wind != nil);
ASSERT(rsrcMap != nil);
ASSERT(sContainers.count(SResourceID(rsrcMap->GetType(), id)) == 0);
mBinding.left = true;
mBinding.right = true;
mBinding.top = true;
mBinding.bottom = true;
wind->AddSubPane(this); // do this here so we're the right type
mDoc = dynamic_cast<CDocument*>(wind->GetSuperCommander());
ASSERT(mDoc != nil);
mDoc->AddReference();
mRsrcMap = rsrcMap;
mType = rsrcMap->GetType();
mRsrcID = id;
mSettingUp = false;
mSnapToGrid = true;
mShowGrid = true;
mGridSize = TSize(10, 10);
mShowPaneNames = false;
mShowClassNames = false;
mShowPaneEdges = true;
THandle data = mRsrcMap->GetResourceData(mRsrcID);
if (data.GetSize() > 0 && dynamic_cast<CViewWindow*>(wind) != nil) {
TInHandleStream stream(data);
mSettingUp = true;
TPane* pane = this->CreatePane(stream, this);
this->DoStreamExtrasIn(stream);
this->DecoratePane(pane);
mSettingUp = false;
wind->SetSize(pane->GetSize());
pane->SetLocation(kZeroPt);
}
sContainers.insert(ContainerEntry(SResourceID(mType, mRsrcID), this));
mRsrcMap->AddListener(this);
wind->SetLatentTarget(this);
MCommander::AddBehaviorToFront(new CTabBehavior);
}
//---------------------------------------------------------------
//
// CViewContainer::Create [static]
//
//---------------------------------------------------------------
MReanimatable* CViewContainer::Create(MReanimatable* parent)
{
TView* view = dynamic_cast<TView*>(parent);
if (view != nil && view->HasAttribute("Editing"))
return new CViewContainer(dynamic_cast<TWindow*>(parent));
else
return new TView("????", dynamic_cast<TView*>(parent), TRect(0, 0, 100, 100));
}
//---------------------------------------------------------------
//
// CViewContainer::SetResourceID
//
//---------------------------------------------------------------
void CViewContainer::SetResourceID(CResourceMap* rsrcMap, ResID id)
{
ASSERT(rsrcMap != nil);
ASSERT(mRsrcMap == nil);
ASSERT(sContainers.count(SResourceID(rsrcMap->GetType(), id)) == 0);
mRsrcMap = rsrcMap;
mType = rsrcMap->GetType();
mRsrcID = id;
sContainers.insert(ContainerEntry(SResourceID(mType, mRsrcID), this));
mRsrcMap->AddListener(this);
}
//---------------------------------------------------------------
//
// CViewContainer::GetContainer [static]
//
//---------------------------------------------------------------
CViewContainer* CViewContainer::GetContainer(ResType type, ResID id)
{
CViewContainer* container = nil;
ContainerMap::iterator iter = sContainers.find(SResourceID(type, id));
if (iter != sContainers.end())
container = (*iter).second;
return container;
}
//---------------------------------------------------------------
//
// CViewContainer::UpdateResource
//
//---------------------------------------------------------------
void CViewContainer::UpdateResource()
{
PRECONDITION(this->GetSuperView() != nil);
if (mRsrcMap != nil && mRsrcMap->HasResource(mRsrcID)) {
THandle data = mRsrcMap->GetResourceData(mRsrcID);
data.Detach();
data.SetSize(0);
{
TOutHandleStream stream(data);
TWindow* window = dynamic_cast<TWindow*>(this->GetTopView());
if (dynamic_cast<CViewWindow*>(window) != nil) {
if (mSubPanes->size() == 1) {
TPane* pane = mSubPanes->front();
pane->Externalize(stream);
this->DoStreamExtrasOut(stream);
} else
ASSERT(mSubPanes->size() == 0);
} else
window->Externalize(stream);
}
mRsrcMap->SetResourceData(mRsrcID, data);
}
POSTCONDITION(true);
}
//---------------------------------------------------------------
//
// CViewContainer::HasSelection
//
//---------------------------------------------------------------
bool CViewContainer::HasSelection() const
{
bool has = false;
TSubPaneIterator iter = this->begin(kRecursive);
while (iter != this->end() && !has) {
TPane* pane = *iter;
++iter;
has = this->IsSelected(pane);
}
return has;
}
//---------------------------------------------------------------
//
// CViewContainer::HasMoreThanOneSelection
//
//---------------------------------------------------------------
bool CViewContainer::HasMoreThanOneSelection() const
{
long count = 0;
TSubPaneIterator iter = this->begin(kRecursive);
while (iter != this->end() && count < 2) {
TPane* pane = *iter;
++iter;
if (this->IsSelected(pane))
count++;
}
return count == 2;
}
//---------------------------------------------------------------
//
// CViewContainer::IsSelected
//
//---------------------------------------------------------------
bool CViewContainer::IsSelected(TPane* pane) const
{
ASSERT(pane != nil);
return pane->FindAdorner("CHandleAdorner") != nil;
}
//---------------------------------------------------------------
//
// CViewContainer::Select
//
//---------------------------------------------------------------
void CViewContainer::Select(TPane* pane, bool extend, bool toggle)
{
PRECONDITION(pane == nil || this->IsSubPane(pane));
ASSERT(pane != this);
if (extend) {
if (pane != nil && !this->IsSelected(pane) && !this->ParentIsSelected(pane))
this->DoSelect(pane);
} else if (toggle) {
if (pane != nil) {
if (this->IsSelected(pane))
this->DoDeselect(pane);
else if (!this->ParentIsSelected(pane))
this->DoSelect(pane);
}
} else {
TSubPaneIterator iter = this->begin(kRecursive);
while (iter != this->end()) {
TPane* subPane = *iter;
++iter;
if (this->IsSelected(subPane) && subPane != pane)
this->DoDeselect(subPane);
}
if (pane != nil && !this->IsSelected(pane))
this->DoSelect(pane);
}
POSTCONDITION(true);
}
//---------------------------------------------------------------
//
// CViewContainer::HandleMouseDown
//
//---------------------------------------------------------------
bool CViewContainer::HandleMouseDown(const TMouseEvent& event)
{
return TPane::HandleMouseDown(event); // don't give subPane's a chance to handle the event
}
//---------------------------------------------------------------
//
// CViewContainer::HandleMouseUp
//
//---------------------------------------------------------------
bool CViewContainer::HandleMouseUp(const TMouseEvent& event)
{
return TPane::HandleMouseUp(event); // don't give subPane's a chance to handle the event
}
//---------------------------------------------------------------
//
// CViewContainer::HandleContextMenu
//
//---------------------------------------------------------------
bool CViewContainer::HandleContextMenu(const TMouseEvent& event)
{
return TPane::HandleContextMenu(event); // don't give subPane's a chance to handle the event
}
//---------------------------------------------------------------
//
// CViewContainer::HandleAdjustCursor
//
//---------------------------------------------------------------
bool CViewContainer::HandleAdjustCursor(const TEvent& event)
{
return TPane::HandleAdjustCursor(event); // don't give subPane's a chance to handle the event
}
#pragma mark ハ
//---------------------------------------------------------------
//
// CViewContainer::Invariant
//
//---------------------------------------------------------------
void CViewContainer::Invariant() const
{
Inherited::Invariant();
ASSERT(mGridSize.width > 0);
ASSERT(mGridSize.height > 0);
// If we're in a CViewWindow then we're editing a pane instead
// of a window and the CViewWindow can have only one subPane.
TView* superView = this->GetSuperView();
if (dynamic_cast<CViewWindow*>(superView) != nil)
ASSERT(mSubPanes->size() <= 1);
// View should be in a window and the super commander should
// be the window.
if (superView != nil) {
TWindow* window = dynamic_cast<TWindow*>(superView);
ASSERT(window != nil);
ASSERT(this->GetSuperCommander() == window);
}
// 'this' should not have the edit adorners
ASSERT(TView::FindAdorner("COutlineAdorner") == nil);
ASSERT(TView::FindAdorner("CHandleAdorner") == nil);
ASSERT(TView::FindAdorner("CPaneNameAdorner") == nil);
ASSERT(TView::FindAdorner("CClassNameAdorner") == nil);
// For each pane we're editing:
#if DEBUG
if (gIntenseDebugging && !mSettingUp) {
TSubPaneIterator iter = this->begin(kRecursive);
while (iter != this->end()) {
TPane* pane = *iter;
++iter;
// none of them should have the target
if (MCommander* commander = dynamic_cast<MCommander*>(pane))
ASSERT(!commander->IsTarget());
// make sure they have the right behaviors and adorners
if (mShowPaneEdges)
ASSERT(pane->FindAdorner("COutlineAdorner") != nil);
if (mShowPaneNames)
ASSERT(pane->FindAdorner("CPaneNameAdorner") != nil);
if (mShowClassNames)
ASSERT(pane->FindAdorner("CClassNameAdorner") != nil);
if (this->IsSelected(pane)) {
// if they're selected they get a few additional behaviors
// and adorners
ASSERT(pane->FindAdorner("CHandleAdorner") != nil);
// subPanes of a selected view shouldn't be selected.
if (TView* view = dynamic_cast<TView*>(pane)) {
TSubPaneIterator iter2 = view->begin(kRecursive);
while (iter2 != view->end()) {
TPane* subPane = *iter2;
++iter2;
ASSERT(!this->IsSelected(subPane));
}
}
}
}
}
#endif
}
//---------------------------------------------------------------
//
// CViewContainer::OnDraw
//
//---------------------------------------------------------------
void CViewContainer::OnDraw(TCanvas& canvas, const TRegion& dirtyRgn)
{
TRegionShape::Fill(canvas, dirtyRgn, kRGBWhite);
if (mShowGrid) {
TRect extent = this->GetExtent();
SPen pen(kRGBGray);
GetIndPattern(&pen.pattern, 0, 26);
long h = mGridSize.width;
while (h < extent.right) {
TLineShape::Draw(canvas, TPoint(h, extent.top), TPoint(h, extent.bottom), pen);
h += mGridSize.width;
}
long v = mGridSize.height;
while (v < extent.bottom) {
TLineShape::Draw(canvas, TPoint(extent.left, v), TPoint(extent.right, v), pen);
v += mGridSize.height;
}
}
}
//---------------------------------------------------------------
//
// CViewContainer::OnMouseDown
//
//---------------------------------------------------------------
bool CViewContainer::OnMouseDown(const TMouseEvent& event)
{
TPane* pane = this->FindPane(event.GetPosition());
if (event.GetClickCount() == 2) {
if (pane != nil) {
if (pane != this)
this->Select(pane);
CPaneEditDialog::EditPane(pane);
}
} else if (event.GetClickCount() == 1) {
if (event.WasCommandKeyDown()) {
TTracker* tracker = new TSelectPanesTracker(this, event.GetPosition(), event.WasShiftKeyDown());
tracker->Post();
} else if (IsKeyDown(kSpaceKeyCode)) {
this->DoDragWindow(event.GetGlobalPosition());
} else if (pane == this) {
this->Select(nil);
} else if (pane != nil) {
if (this->IsSelected(pane) && this->ClickedHandle(pane, event))
;
else if (::WaitMouseMoved(event.GetGlobalPosition())) {
if (!this->IsSelected(pane)) {
this->Select(pane, event.WasShiftKeyDown());
this->HandleUpdate();
}
this->HandleDragStart(event);
} else
this->Select(pane, event.WasShiftKeyDown(), event.WasCommandKeyDown());
}
}
return kHandled;
}
//---------------------------------------------------------------
//
// CViewContainer::OnContextMenu
//
//---------------------------------------------------------------
bool CViewContainer::OnContextMenu(const TMouseEvent& event)
{
TPane* pane = this->FindPane(event.GetPosition());
if (pane != nil && pane != this && !this->IsSelected(pane)) {
this->Select(pane);
this->HandleUpdate();
}
TContextMenu* popup = new TContextMenu(this, event.GetGlobalPosition(), pane != nil && pane != this ? 319 : 320);
popup->Post();
return kHandled;
}
//---------------------------------------------------------------
//
// CViewContainer::OnAdjustCursor
//
//---------------------------------------------------------------
bool CViewContainer::OnAdjustCursor(const TEvent& event)
{
if (event.WasCommandKeyDown())
UCursorUtils::SetCursor(kCrossHairCursor);
else if (IsKeyDown(kSpaceKeyCode))
UCursorUtils::SetCursor(kOpenHandCursor);
else
UCursorUtils::SetCursor(kArrowCursor);
return kHandled;
}
//---------------------------------------------------------------
//
// CViewContainer::OnAdjustSubPaneSizes
//
//---------------------------------------------------------------
void CViewContainer::OnAdjustSubPaneSizes(const TPoint& delta, bool redraw)
{
#pragma unused(delta, redraw)
// do nothing
}
//---------------------------------------------------------------
//
// CViewContainer::DoStreamExtrasIn
//
//---------------------------------------------------------------
void CViewContainer::DoStreamExtrasIn(TInStream& stream)
{
try {
Inherited::DoStreamExtrasIn(stream);
if (this->HasAttribute("Window Frame")) {
TRectAttribute* frameAttr = dynamic_cast<TRectAttribute*>(this->GetAttribute("Window Frame"));
TWindow* window = dynamic_cast<TWindow*>(this->GetTopView());
window->SetFrame(frameAttr->GetValue());
window->ForceOnScreen();
}
if (this->HasAttribute("Snap To Grid")) {
TBoolAttribute* snapGridAttr = dynamic_cast<TBoolAttribute*>(this->GetAttribute("Snap To Grid"));
mSnapToGrid = snapGridAttr->GetValue();
}
if (this->HasAttribute("Show Grid")) {
TBoolAttribute* showGridAttr = dynamic_cast<TBoolAttribute*>(this->GetAttribute("Show Grid"));
mShowGrid = showGridAttr->GetValue();
}
if (this->HasAttribute("Grid Size")) {
TSizeAttribute* gridSizeAttr = dynamic_cast<TSizeAttribute*>(this->GetAttribute("Grid Size"));
mGridSize = gridSizeAttr->GetValue();
}
if (this->HasAttribute("Show Pane Names")) {
TBoolAttribute* paneNameAttr = dynamic_cast<TBoolAttribute*>(this->GetAttribute("Show Pane Names"));
mShowPaneNames = paneNameAttr->GetValue();
}
if (this->HasAttribute("Show Class Names")) {
TBoolAttribute* classNameAttr = dynamic_cast<TBoolAttribute*>(this->GetAttribute("Show Class Names"));
mShowClassNames = classNameAttr->GetValue();
}
if (this->HasAttribute("Show Pane Edges")) {
TBoolAttribute* edgesAttr = dynamic_cast<TBoolAttribute*>(this->GetAttribute("Show Pane Edges"));
mShowPaneEdges = edgesAttr->GetValue();
}
} catch (const TBaseException& e) {
ReportError(LoadAppString("Couldn't read the view's preferences"), e);
} catch (...) {
ReportError(LoadAppString("Couldn't read the view's preferences"), LoadAppString("Unknown Error"));
}
}
//---------------------------------------------------------------
//
// CViewContainer::DoStreamExtrasOut
//
//---------------------------------------------------------------
void CViewContainer::DoStreamExtrasOut(TOutStream& stream) const
{
CViewContainer* thisPtr = const_cast<CViewContainer*>(this);
try {
// Save the window's frame.
if (!this->HasAttribute("Window Frame"))
thisPtr->AddAttribute("Window Frame", new TRectAttribute);
TRectAttribute* frameAttr = dynamic_cast<TRectAttribute*>(this->GetAttribute("Window Frame"));
TWindow* window = dynamic_cast<TWindow*>(this->GetTopView());
frameAttr->SetValue(window->GetFrame());
// Save the snap to grid flag.
if (!this->HasAttribute("Snap To Grid"))
thisPtr->AddAttribute("Snap To Grid", new TBoolAttribute);
TBoolAttribute* snapGridAttr = dynamic_cast<TBoolAttribute*>(this->GetAttribute("Snap To Grid"));
snapGridAttr->SetValue(mSnapToGrid);
// Save the show grid flag.
if (!this->HasAttribute("Show Grid"))
thisPtr->AddAttribute("Show Grid", new TBoolAttribute);
TBoolAttribute* showGridAttr = dynamic_cast<TBoolAttribute*>(this->GetAttribute("Show Grid"));
showGridAttr->SetValue(mShowGrid);
// Save the grid size.
if (!this->HasAttribute("Grid Size"))
thisPtr->AddAttribute("Grid Size", new TSizeAttribute);
TSizeAttribute* gridSizeAttr = dynamic_cast<TSizeAttribute*>(this->GetAttribute("Grid Size"));
gridSizeAttr->SetValue(mGridSize);
// Save the show pane names flag.
if (!this->HasAttribute("Show Pane Names"))
thisPtr->AddAttribute("Show Pane Names", new TBoolAttribute);
TBoolAttribute* paneNameAttr = dynamic_cast<TBoolAttribute*>(this->GetAttribute("Show Pane Names"));
paneNameAttr->SetValue(mShowPaneNames);
// Save the show class names flag.
if (!this->HasAttribute("Show Class Names"))
thisPtr->AddAttribute("Show Class Names", new TBoolAttribute);
TBoolAttribute* classNameAttr = dynamic_cast<TBoolAttribute*>(this->GetAttribute("Show Class Names"));
classNameAttr->SetValue(mShowClassNames);
// Save the show pane edges flag.
if (!this->HasAttribute("Show Pane Edges"))
thisPtr->AddAttribute("Show Pane Edges", new TBoolAttribute);
TBoolAttribute* edgesAttr = dynamic_cast<TBoolAttribute*>(this->GetAttribute("Show Pane Edges"));
edgesAttr->SetValue(mShowPaneEdges);
} catch (const TBaseException& e) {
ReportError(LoadAppString("Couldn't save the view's preferences"), e);
} catch (...) {
ReportError(LoadAppString("Couldn't save the view's preferences"), LoadAppString("Unknown Error"));
}
Inherited::DoStreamExtrasOut(stream);
}
//---------------------------------------------------------------
//
// CViewContainer::OnAddDragData
//
//---------------------------------------------------------------
void CViewContainer::OnAddDragData(TDragSession& session, const TMouseEvent& event)
{
#pragma unused(event)
ASSERT(this->HasSelection());
bool firstPane = true;
TSubPaneIterator iter = this->begin(kRecursive);
while (iter != this->end()) {
TPane* pane = *iter;
++iter;
if (this->IsSelected(pane)) {
// add the flavor
SResource rsrc(kIndeterminateID);
{
TOutHandleStream stream(rsrc.data);
pane->Externalize(stream);
}
rsrc.AddData(session, (ItemReference) pane, 'View', flavorSenderOnly);
// add the drag region
TRect dragRect = pane->GetExtent();
dragRect = pane->LocalToPort(dragRect);
dragRect = pane->PortToGlobal(dragRect);
session.AddDragRgn((ItemReference) pane, dragRect);
}
}
}
//---------------------------------------------------------------
//
// CViewContainer::OnDragInput
//
//---------------------------------------------------------------
void CViewContainer::OnDragInput(TMouseEvent& event, const TDragSession& session)
{
MConstrainedDragTarget::OnDragInput(event, session);
// Snap the first item into place.
if (mSnapToGrid) {
TPoint mouse = event.GetPosition();
TPoint constrain = mouse + msItemOffset;
TWindow* window = dynamic_cast<TWindow*>(this->GetTopView());
constrain -= window->GetFrame()[topLeft];
TPoint constrained;
constrained.h = ((constrain.h + mGridSize.width/2)/mGridSize.width)*mGridSize.width;
constrained.v = ((constrain.v + mGridSize.height/2)/mGridSize.height)*mGridSize.height;
TPoint delta = constrained - constrain;
event.SetPosition(mouse + delta);
}
}
//---------------------------------------------------------------
//
// CViewContainer::OnGetDragWindow
//
//---------------------------------------------------------------
WindowRef CViewContainer::OnGetDragWindow() const
{
TView* topView = this->GetTopView();
TWindow* window = dynamic_cast<TWindow*>(topView);
return window->GetWindowRef();
}
//---------------------------------------------------------------
//
// CViewContainer::OnGetDropRegion
//
//---------------------------------------------------------------
TRegion CViewContainer::OnGetDropRegion()
{
TRect dropRect;
dropRect = this->GetExtent();
dropRect = this->LocalToPort(dropRect);
dropRect = this->PortToGlobal(dropRect);
return dropRect;
}
//---------------------------------------------------------------
//
// CViewContainer::OnGetDropHiliteRegion
//
//---------------------------------------------------------------
TRegion CViewContainer::OnGetDropHiliteRegion(const TDragSession& session)
{
TRect extent = kZeroRect;
TView* view = this->FindDropTarget(session);
if (view != nil) {
extent = view->GetExtent();
extent = view->LocalToPort(extent);
extent = view->PortToGlobal(extent);
msDragLeftTarget = true;
}
return extent;
}
//---------------------------------------------------------------
//
// CViewContainer::OnCanAcceptDrag
//
//---------------------------------------------------------------
bool CViewContainer::OnCanAcceptDrag(ItemReference item, const TDragSession& session)
{
bool accept = false;
if (session.HasFlavor(item, 'View'))
accept = this->FindDropTarget(session) != nil;
return accept;
}
//---------------------------------------------------------------
//
// CViewContainer::OnDragReceive
//
//---------------------------------------------------------------
void CViewContainer::OnDragReceive(const TDragSession& session)
{
// Find the view the mouse was over.
TView* view = this->FindDropTarget(session);
if (view != nil) {
// Get the undo context (we need to do this because the
// window may not be the frontmost regular window).
TView* topView = this->GetTopView();
TWindow* window = dynamic_cast<TWindow*>(topView);
TUndoMgr* context = window->GetUndoContext();
CAddSubPanesCommand* command = new CAddSubPanesCommand(this, view, context);
try {
mSettingUp = true;
// Drop the panes into the view.
long count = session.GetItemCount();
for (long index = 0; index < count; index++) {
ItemReference item = session.GetItemReference(index);
if (session.HasFlavor(item, 'View')) {
TPane* pane = nil;
{
// create the new pane (some pane classes require
// a port during construction so we'll temporarily
// hook it into the view hierarchy)
SResource rsrc(session, item, 'View');
TInHandleStream stream(rsrc.data);
pane = this->CreatePane(stream, view);
view->RemoveSubPane(pane);
}
// find out where it was dropped
TPoint mouse = session.GetItemBounds(item)[topLeft];
mouse = view->GlobalToPort(mouse);
mouse = view->PortToLocal(mouse);
// move the pane to the correct position (do this
// here to minimize invalidation)
pane->SetLocation(mouse);
// add the appropiate adorners and behaviors
this->DecoratePane(pane);
if (!this->IsSelected(pane))
this->DoSelect(pane);
// insert the new panes into the view hierarchy
command->AddPane(pane);
}
}
command->Post();
} catch (...) {
delete command;
throw;
}
}
mSettingUp = false;
}
//---------------------------------------------------------------
//
// CViewContainer::OnDragMoved
//
//---------------------------------------------------------------
void CViewContainer::OnDragMoved(const TDragSession& session)
{
// Find the view the mouse was over.
TView* view = this->FindDropTarget(session);
if (view != nil) {
// Get the undo context (we need to do this because the
// window may not be the frontmost regular window).
TView* topView = this->GetTopView();
TWindow* window = dynamic_cast<TWindow*>(topView);
TUndoMgr* context = window->GetUndoContext();
CMovePanesCommand* command = new CMovePanesCommand(this, view, context);
try {
// Move each pane to its new location.
long count = session.GetItemCount();
for (long index = 0; index < count; index++) {
ItemReference item = session.GetItemReference(index);
if (session.HasFlavor(item, 'View')) {
// find out which pane we're moving
TPane* pane = reinterpret_cast<TPane*>(item);
ASSERT(this->IsSubPane(pane));
// find out where it was dropped
TPoint globalLoc = session.GetItemBounds(item)[topLeft];
TPoint portLoc = view->GlobalToPort(globalLoc);
TPoint superLoc = view->PortToLocal(portLoc);
// move the pane to the correct position
command->AddPane(pane, superLoc);
}
}
command->Post();
} catch (...) {
delete command;
throw;
}
}
}
//---------------------------------------------------------------
//
// CViewContainer::OnReanimated
//
//---------------------------------------------------------------
void CViewContainer::OnReanimated()
{
ASSERT(mDoc == nil);
Inherited::OnReanimated();
TWindow* window = dynamic_cast<TWindow*>(this->GetTopView());
ASSERT(window != nil);
mDoc = dynamic_cast<CDocument*>(window->GetSuperCommander());
ASSERT(mDoc != nil);
mDoc->AddReference(); // make sure doc isn't deleted before we get a chance to update it
}
//---------------------------------------------------------------
//
// CViewContainer::OnStreamOut
//
// When a window is reanimated a TView is created instead of the
// CViewContainer. To make this work properly we need to bypass
// the TCachedView streaming (this is OK since we're just using
// the system colors). Note that this is only called when editing
// windows; panes are streamed out directly (see UpdateResource).
//
//---------------------------------------------------------------
void CViewContainer::OnStreamOut(TOutStream& stream) const
{
ASSERT(dynamic_cast<CViewWindow*>(this->GetTopView()) == nil);
TView::OnStreamOut(stream);
}
//---------------------------------------------------------------
//
// CViewContainer::OnStreamIn
//
//---------------------------------------------------------------
void CViewContainer::OnStreamIn(TInStream& stream, long version)
{
ASSERT(dynamic_cast<CViewWindow*>(this->GetTopView()) == nil);
mSettingUp = true; // ・・・ハshould probably use a stack based class to set this
TView::OnStreamIn(stream, version);
TSubPaneIterator iter = this->begin();
while (iter != this->end()) {
TPane* subPane = *iter;
++iter;
this->DecoratePane(subPane);
}
mSettingUp = false;
}
//---------------------------------------------------------------
//
// CViewContainer::OnBroadcast
//
//---------------------------------------------------------------
void CViewContainer::OnBroadcast(const SResourceMapMessage& mesg)
{
if (mesg.rsrcMap == mRsrcMap) {
if (mesg.message == kSetResourceID && mesg.oldRsrc.id == mRsrcID) {
sContainers.erase(SResourceID(mType, mRsrcID));
mRsrcID = mesg.newRsrc.id;
sContainers.insert(ContainerEntry(SResourceID(mType, mRsrcID), this));
}
}
}
//---------------------------------------------------------------
//
// CViewContainer::OnKeyDown
//
//---------------------------------------------------------------
bool CViewContainer::OnKeyDown(const TKeyEvent& event)
{
bool handled = true;
char ch = event.GetChar();
short key = event.GetKey();
if (ch == kLeftArrowChar || ch == kRightArrowChar || ch == kUpArrowChar || ch == kDownArrowChar)
this->NudgePanes(ch);
else {
if (ch == kBackspaceChar)
key = kClearKey;
switch (key) {
case kClearKey:
if (this->HasSelection())
this->OnMenuCommand(kClearCmd);
break;
case kF2Key:
if (this->HasSelection())
this->OnMenuCommand(kCutCmd);
break;
case kF3Key:
if (this->HasSelection())
this->OnMenuCommand(kCopyCmd);
break;
case kF4Key:
if (this->CanPaste())
this->OnMenuCommand(kPasteCmd);
break;
default:
handled = false;
}
}
return handled;
}
//---------------------------------------------------------------
//
// CViewContainer::OnMenuCommand
//
//---------------------------------------------------------------
bool CViewContainer::OnMenuCommand(const MenuCommand& cmd)
{
bool handled = true;
TCommand* command = nil;
if (cmd == kCutCmd && this->HasSelection()) {
command = new CCutPanesCommand(this);
command->Post();
} else if (cmd == kCopyCmd && this->HasSelection()) {
command = new CCopyPanesCommand(this);
command->Post();
} else if (cmd == kPasteCmd && this->CanPaste()) {
command = new CPastePanesCommand(this, this->GetPasteView());
command->Post();
} else if (cmd == kClearCmd && this->HasSelection()) {
command = new CDeletePanesCommand(this);
command->Post();
} else if (cmd == kDuplicateCmd && this->CanDuplicate()) {
command = new CDuplicatePanesCommand(this);
command->Post();
} else if (cmd == kAlignLeftCmd) {
command = new CAlignLeftCommand(this);
command->Post();
} else if (cmd == kAlignRightCmd) {
command = new CAlignRightCommand(this);
command->Post();
} else if (cmd == kAlignTopCmd) {
command = new CAlignTopCommand(this);
command->Post();
} else if (cmd == kAlignBottomCmd) {
command = new CAlignBottomCommand(this);
command->Post();
} else if (cmd == kSnapToGridCmd) {
mSnapToGrid = !mSnapToGrid;
this->UpdateResource();
} else if (cmd == kEditGridCmd) {
if (CGridSizeDialog::Pose(&mGridSize)) {
if (mShowGrid)
this->Invalidate();
this->UpdateResource();
}
} else if (cmd == kShowGridCmd) {
mShowGrid = !mShowGrid;
this->Invalidate();
this->UpdateResource();
} else if (cmd == kShowPaneEdgesCmd) {
mShowPaneEdges = !mShowPaneEdges;
this->AddPaneEdgeAdorners();
this->UpdateResource();
} else if (cmd == kShowPaneNamesCmd) {
mShowPaneNames = !mShowPaneNames;
this->AddPaneNameAdorners();
this->UpdateResource();
} else if (cmd == kShowClassNamesCmd) {
mShowClassNames = !mShowClassNames;
this->AddClassNameAdorners();
this->UpdateResource();
} else
handled = false;
return handled;
}
//---------------------------------------------------------------
//
// CViewContainer::OnCommandStatus
//
//---------------------------------------------------------------
bool CViewContainer::OnCommandStatus(const MenuCommand& command, SCommandStatus& status)
{
bool handled = true;
if (command == kCutCmd) {
status.enabled = this->HasSelection();
} else if (command == kCopyCmd) {
status.enabled = this->HasSelection();
} else if (command == kPasteCmd) {
status.enabled = this->CanPaste();
} else if (command == kClearCmd) {
status.enabled = this->HasSelection();
} else if (command == kDuplicateCmd) {
status.enabled = this->CanDuplicate();
} else if (command == kAlignLeftCmd) {
status.enabled = this->HasMoreThanOneSelection();
} else if (command == kAlignRightCmd) {
status.enabled = this->HasMoreThanOneSelection();
} else if (command == kAlignTopCmd) {
status.enabled = this->HasMoreThanOneSelection();
} else if (command == kAlignBottomCmd) {
status.enabled = this->HasMoreThanOneSelection();
} else if (command == kSnapToGridCmd) {
status.enabled = true;
if (mSnapToGrid)
status.name = LoadIndString(258, 1);
else
status.name = LoadIndString(258, 2);
} else if (command == kEditGridCmd) {
status.enabled = true;
} else if (command == kShowGridCmd) {
status.enabled = true;
if (mShowGrid)
status.name = LoadIndString(258, 3);
else
status.name = LoadIndString(258, 4);
} else if (command == kShowPaneEdgesCmd) {
status.enabled = true;
if (mShowPaneEdges)
status.name = LoadIndString(258, 5);
else
status.name = LoadIndString(258, 6);
} else if (command == kShowPaneNamesCmd) {
status.enabled = true;
if (mShowPaneNames)
status.name = LoadIndString(258, 7);
else
status.name = LoadIndString(258, 8);
} else if (command == kShowClassNamesCmd) {
status.enabled = true;
if (mShowClassNames)
status.name = LoadIndString(258, 9);
else
status.name = LoadIndString(258, 10);
} else
handled = false;
return handled;
}
#pragma mark ハ
//---------------------------------------------------------------
//
// CViewContainer::FindDropTarget
//
//---------------------------------------------------------------
TView* CViewContainer::FindDropTarget(const TDragSession& session)
{
// Find the mouse position.
TPoint mouse = session.GetMouse();
mouse = this->GlobalToPort(mouse);
mouse = this->PortToLocal(mouse);
// Find the view the mouse is over.
TView* view = this->FindView(mouse);
// If we're dragging the pane within the source window don't
// drop the pane inside a selected view (this would lead to
// some bad craziness because we're dragging the selected panes).
if (view != nil && msSourceTarget == this) {
while (view != this && this->InSelection(view))
view = view->GetSuperView();
}
// If the target is the container we need to check the superView.
// If it's a CViewWindow the container can only have one subPane.
if (view == this) {
if (dynamic_cast<CViewWindow*>(this->GetSuperView()) != nil) {
if (session.GetItemCount() > 1)
view = nil;
else if (mSubPanes->size() == 1) {
ItemReference item = session.GetItemReference(0);
TPane* pane = reinterpret_cast<TPane*>(item);
if (pane != mSubPanes->front())
view = nil;
}
}
}
return view;
}
//---------------------------------------------------------------
//
// CViewContainer::InSelection
//
//---------------------------------------------------------------
bool CViewContainer::InSelection(TPane* pane) const
{
ASSERT(pane != nil);
bool in = this->IsSelected(pane);
if (!in) {
TView* view = pane->GetSuperView();
while (view != this && !in) {
in = this->IsSelected(view);
view = view->GetSuperView();
}
}
return in;
}
//---------------------------------------------------------------
//
// CViewContainer::CanDuplicate
//
//---------------------------------------------------------------
bool CViewContainer::CanDuplicate() const
{
bool can = this->HasSelection();
if (can && dynamic_cast<CViewWindow*>(this->GetSuperView()) != nil) {
TPane* pane = mSubPanes->front();
if (this->IsSelected(pane))
can = false;
}
return can;
}
//---------------------------------------------------------------
//
// CViewContainer::CanPaste
//
//---------------------------------------------------------------
bool CViewContainer::CanPaste() const
{
return ::InScrap('View') && this->GetPasteView() != nil;
}
//---------------------------------------------------------------
//
// CViewContainer::GetPasteView
//
//---------------------------------------------------------------
TView* CViewContainer::GetPasteView() const
{
TView* view = nil;
if (dynamic_cast<CViewWindow*>(this->GetSuperView()) == nil)
view = const_cast<CViewContainer*>(this);
else if (mSubPanes->size() == 0) {
if (::InScrap('View')) {
THandle data = ::GetScrap('View');
TInHandleStream stream(data);
SResource rsrc;
stream >> rsrc;
if (stream.AtEnd())
view = const_cast<CViewContainer*>(this);
}
} else {
TPane* pane = mSubPanes->front();
view = dynamic_cast<TView*>(pane);
}
return view;
}
//---------------------------------------------------------------
//
// CViewContainer::NudgePanes
//
//---------------------------------------------------------------
void CViewContainer::NudgePanes(char key)
{
if (this->HasSelection()) {
CNudgePaneCommand* command = dynamic_cast<CNudgePaneCommand*>(TUndoMgr::GetContext()->GetUndoCommand());
if (command == nil || !command->CanNudge(this, key)) {
command = new CNudgePaneCommand(this, key);
command->Post();
}
command->Nudge();
this->UpdateResource();
}
}
//---------------------------------------------------------------
//
// CViewContainer::ParentIsSelected
//
//---------------------------------------------------------------
bool CViewContainer::ParentIsSelected(TPane* pane) const
{
ASSERT(pane != nil);
bool selected = false;
TView* super = pane->GetSuperView();
while (super != nil && !selected) {
selected = this->IsSelected(super);
super = super->GetSuperView();
}
return selected;
}
//---------------------------------------------------------------
//
// CViewContainer::DoSelect
//
//---------------------------------------------------------------
void CViewContainer::DoSelect(TPane* pane)
{
ASSERT(pane != nil);
ASSERT(pane != this);
ASSERT(!this->IsSelected(pane));
pane->AddAdorner(new CHandleAdorner);
if (TView* view = dynamic_cast<TView*>(pane)) {
TSubPaneIterator iter = view->begin(kRecursive);
while (iter != view->end()) {
TPane* subPane = *iter;
++iter;
if (this->IsSelected(subPane))
this->DoDeselect(subPane);
}
}
}
//---------------------------------------------------------------
//
// CViewContainer::DoDeselect
//
//---------------------------------------------------------------
void CViewContainer::DoDeselect(TPane* pane)
{
ASSERT(pane != nil);
ASSERT(pane != this);
ASSERT(this->IsSubPane(pane));
ASSERT(this->IsSelected(pane));
TAdorner* adorner = pane->FindAdorner("CHandleAdorner");
delete adorner;
}
//---------------------------------------------------------------
//
// CViewContainer::DoDragWindow
//
//---------------------------------------------------------------
void CViewContainer::DoDragWindow(const TPoint& globalPos)
{
GrafPtr port;
GetWMgrPort(&port);
TSetPort setPort(port);
TRect extent = this->GetExtent();
extent = this->LocalToPort(extent);
extent = this->PortToGlobal(extent);
TRegion dragRgn(extent);
TRegion grayRgn = GetGrayRgn();
TRect limitRect = grayRgn.GetEnclosingRect();
limitRect.Inset(4, 4);
TSetClip clip(grayRgn);
long delta = DragGrayRgn(dragRgn, globalPos, limitRect, limitRect, noConstraint, nil);
short dx = LoWord(delta);
short dy = HiWord(delta);
if (dx != 0 || dy != 0) {
TView* topView = this->GetTopView();
TWindow* window = dynamic_cast<TWindow*>(topView);
TPoint newLoc = window->GetLocation() + TPoint(dx, dy);
window->SetLocation(newLoc);
}
}
//---------------------------------------------------------------
//
// CViewContainer::DecoratePane
//
//---------------------------------------------------------------
void CViewContainer::DecoratePane(TPane* pane, bool add)
{
ASSERT(pane != nil);
if (add) {
if (mShowPaneEdges && pane->FindAdorner("COutlineAdorner") == nil)
pane->AddAdorner(new COutlineAdorner);
if (mShowPaneNames && pane->FindAdorner("CPaneNameAdorner") == nil)
pane->AddAdorner(new CPaneNameAdorner);
if (mShowClassNames && pane->FindAdorner("CClassNameAdorner") == nil)
pane->AddAdorner(new CClassNameAdorner);
} else {
TAdorner* adorner = pane->FindAdorner("CHandleAdorner");
delete adorner;
adorner = pane->FindAdorner("COutlineAdorner");
delete adorner;
adorner = pane->FindAdorner("CPaneNameAdorner");
delete adorner;
adorner = pane->FindAdorner("CClassNameAdorner");
delete adorner;
}
if (TView* view = dynamic_cast<TView*>(pane)) {
TSubPaneIterator iter = view->begin();
while (iter != view->end()) {
TPane* subPane = *iter;
++iter;
this->DecoratePane(subPane, add);
}
}
}
//---------------------------------------------------------------
//
// CViewContainer::AddPaneEdgeAdorners
//
//---------------------------------------------------------------
void CViewContainer::AddPaneEdgeAdorners()
{
TSubPaneIterator iter = this->begin(kRecursive);
while (iter != this->end()) {
TPane* subPane = *iter;
++iter;
if (mShowPaneEdges) {
if (!subPane->FindAdorner("COutlineAdorner"))
subPane->AddAdorner(new COutlineAdorner);
} else {
TAdorner* adorner = subPane->FindAdorner("COutlineAdorner");
delete adorner;
}
}
}
//---------------------------------------------------------------
//
// CViewContainer::AddPaneNameAdorners
//
//---------------------------------------------------------------
void CViewContainer::AddPaneNameAdorners()
{
TSubPaneIterator iter = this->begin(kRecursive);
while (iter != this->end()) {
TPane* subPane = *iter;
++iter;
if (mShowPaneNames) {
if (!subPane->FindAdorner("CPaneNameAdorner"))
subPane->AddAdorner(new CPaneNameAdorner);
} else {
TAdorner* adorner = subPane->FindAdorner("CPaneNameAdorner");
delete adorner;
}
}
}
//---------------------------------------------------------------
//
// CViewContainer::AddClassNameAdorners
//
//---------------------------------------------------------------
void CViewContainer::AddClassNameAdorners()
{
TSubPaneIterator iter = this->begin(kRecursive);
while (iter != this->end()) {
TPane* subPane = *iter;
++iter;
if (mShowClassNames) {
if (!subPane->FindAdorner("CClassNameAdorner"))
subPane->AddAdorner(new CClassNameAdorner);
} else {
TAdorner* adorner = subPane->FindAdorner("CClassNameAdorner");
delete adorner;
}
}
}
//---------------------------------------------------------------
//
// CViewContainer::CreatePane
//
//---------------------------------------------------------------
TPane* CViewContainer::CreatePane(TInStream& stream, TView* superView)
{
TPane* pane = nil;
long start;
try {
start = stream.GetPosition();
pane = TPane::Create(stream, superView);
} catch (const TReanimateException& e) {
stream.SetPosition(start); // make sure we can restore the stream before asking the user if he wants to retry
if (this->AddBaseClass(e.GetClassName()))
pane = this->CreatePane(stream, superView);
else
throw;
}
return pane;
}
//---------------------------------------------------------------
//
// CViewContainer::AddBaseClass
//
//---------------------------------------------------------------
bool CViewContainer::AddBaseClass(const string& derivedClass)
{
bool added = false;
if (mDoc != nil) {
if (AnswerYes(derivedClass + LoadAppString(" isn't one of the known types. Would you like to define it?"))) {
string baseClass;
if (GetString(LoadAppString("Base Class"), &baseClass)) {
CCustomClasses* custom = mDoc->GetCustomPanes();
custom->AddClass(derivedClass, baseClass);
added = true;
}
}
}
return added;
}
//---------------------------------------------------------------
//
// CViewContainer::ClickedHandle
//
//---------------------------------------------------------------
bool CViewContainer::ClickedHandle(TPane* pane, const TMouseEvent& event)
{
ASSERT(pane != nil);
bool handled = false;
if (event.WasMouseDown()) {
TPoint mouse = event.GetPosition();
mouse = this->LocalToPort(mouse);
mouse = pane->PortToLocal(mouse);
TPoint anchor(-1, -1);
TRect extent = pane->GetExtent();
TRect handle = extent; // top left
handle.right = handle.left + kHandleSize;
handle.bottom = handle.top + kHandleSize;
if (handle.Contains(mouse)) {
anchor.h = extent.right;
anchor.v = extent.bottom;
}
handle = extent; // right top
handle.left = handle.right - kHandleSize;
handle.bottom = handle.top + kHandleSize;
if (handle.Contains(mouse)) {
anchor.h = extent.left;
anchor.v = extent.bottom;
}
handle = extent; // bottom left
handle.right = handle.left + kHandleSize;
handle.top = handle.bottom - kHandleSize;
if (handle.Contains(mouse)) {
anchor.h = extent.right;
anchor.v = extent.top;
}
handle = extent; // right bottom
handle.left = handle.right - kHandleSize;
handle.top = handle.bottom - kHandleSize;
if (handle.Contains(mouse)) {
anchor.h = extent.left;
anchor.v = extent.top;
}
if (anchor != TPoint(-1, -1)) {
TTracker* tracker = new CResizeTracker(pane, anchor, mouse);
tracker->Post();
handled = true;
}
}
return handled;
}